package annotation;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import model.TBackAdminUser;
import model.TBackLog;
import model.VBackAdminUser;
import persistent.factory.DAOFactory;
import util.toolkit.*;

/**
 * @author 张锦盛
 * @E-mail:
 * @version 创建时间：2019-2-18 下午4:29:05
 * @desc 针对controller类中的方法进行增强切入，实现controller方法执行后的数据库日志存储
 */
@Aspect
@Component
public class SystemLogAspect {
	
	/**
	 * 后置通知 用于拦截Controller层记录用户的操作
	 * @param joinPoint 切点
	 * @param rvt 当前操作返回值
	 */
	@AfterReturning(pointcut = "execution(* controller.*.*(..))", returning = "rvt")
	public void getResult(JoinPoint joinPoint, Object rvt) {

		//判断当前操作返回的是什么类型
		//if(vrt instanceof Boolean) boolean b = (Boolean)rvt; else if()
		
		try {
			//获得切入点（被代理对象）的类名  如：controller.MovieController
			String targetName = joinPoint.getTarget().getClass().getName();
			//获得方法（被代理对象）的名称   如：queryMovie()
			String methodName = joinPoint.getSignature().getName();
			//获取传入目标方法的参数对象   如：[{}, org.apache.catalina.connector.RequestFacade@493387d1, org.apache.catalina.connector.ResponseFacade@573e4ef7]
			Object[] arguments = joinPoint.getArgs();
			//根据类（接口）的名称返回该类（接口）对象
			Class targetClass = Class.forName(targetName);
			//根据类对象获取其中的public方法列表
			Method[] methods = targetClass.getMethods();
			
			//定义一个操作类型泳衣接受操作类型
			String operationType = "";
			//定义一个操作描述用以存储操作描述
			String operationDescribe = "";
			//定义一个菜单用以存储操作菜单
			String operationMenu = "";
			//定义一个类路径用以存储操作类路径
			String operationClassPath = "";
			
			//遍历方法列表
			for (Method method : methods) {
				//存在切面引用（增强点）才进入
				if(method.getAnnotation(Log.class) != null && method.getAnnotation(Log.class) != null){
					//遍历的当前方法与切入（代理）方法一致   则执行下面代码
					if (method.getName().equals(methodName)) {
						//获得方法里的所有参数列表
						Class[] clazzs = method.getParameterTypes();
						//比对当前获得的方法参数与切入点（代理获得的参数数量是否一致）
						if (clazzs.length == arguments.length) {
							//得到操作类型
							operationType = method.getAnnotation(Log.class).operationType();
							//得到操作名称
							operationDescribe = method.getAnnotation(Log.class).operationDescribe();
							//得到操作菜单
							operationMenu = method.getAnnotation(Log.class).operationMenu();
							//得到操作的类路径
							operationClassPath = method.getAnnotation(Log.class).operationClassPath();
							break;
						}
					}					
				}			
			}
			
			if(!operationType.equals("") && !operationType.equals(Constant.OPERTATION_QUERY) && !operationDescribe.equals("") 
					&& !operationMenu.equals("") && !operationClassPath.equals("")){
				
				//获得request对象
				HttpServletRequest request = ((ServletRequestAttributes) 
						RequestContextHolder.getRequestAttributes()).getRequest();
				//获得session对象
				HttpSession session = request.getSession();
				//读取session中的用户
				VBackAdminUser backUser = (VBackAdminUser) session.getAttribute("backUser");
			
//				System.out.println("operationType:" + operationType + ",operationName:" + operationDescribe + 
//						",operationMenu:" + operationMenu + ",operationClassPath:" + operationClassPath);
//				
//				System.out.println("执行完毕后检查");
				//生成一个日志对象
				TBackLog backLog = new TBackLog();
				//设置日志编号
				backLog.setBacklogid(UUID.randomUUID().toString());
				backLog.setClassPath(operationClassPath);
				backLog.setMenuName(operationMenu);
				backLog.setOperationDescribe(operationDescribe);
				backLog.setOperationTime(ToolsUtil.tranDate2datetime(new Date()));
				backLog.setOperationType(operationType);
				backLog.setPhone(backUser.getMobile());
				backLog.setRealName(backUser.getRealname());
				backLog.setUserName(backUser.getUserid());
				backLog.setRoleName(backUser.getName());
				DAOFactory.getIBackLogDAO().addBackLog(backLog);
				//System.out.println("-----日志已经保存------");		
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 异常通知 用于拦截记录异常日志
	 * @param joinPoint
	 * @param e
	 */
	// 接收来自参照点方法的异常，并处理
	/*
	 * @AfterThrowing(throwing="ex",pointcut="execution(* controller.*.*(..))")
	 * public void doRecoveryActions(Throwable ex){
	 * System.out.println("目标方法中抛出的异常�? + ex); }
	 */
}